﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using ObjectPoolSandbox;

namespace ObjectPoolSandboxTests
{
    [TestClass]
    public class ObjectPoolTests
    {
        [TestInitialize]
        public void TestInitialize()
        {
            ObjectPool.Reset();
        }

        [TestMethod]
        public void InitializedInstanceReturnedAsRequested()
        {
            PooledObject instance = ObjectPool.Acquire();
            Assert.IsNotNull(instance);
        }

        [TestMethod]
        public void ObjectPoolSupportsCapacity()
        {
            const int capacity = 17;
            ObjectPool.SetCapacity(capacity);
            Assert.AreEqual(capacity, ObjectPool.Capacity);
        }

        [TestMethod]
        public void ObjectPoolDefaultCapacity()
        {
            Assert.AreEqual(10, ObjectPool.Capacity);
        }

        [TestMethod]
        public void DistinctInstancesAreReturnedFromAcquire()
        {
            var first = ObjectPool.Acquire();
            var second = ObjectPool.Acquire();

            Assert.AreNotSame(first, second);
        }

        [TestMethod]
        public void OutOfResourcesExceptionThrownWhenResourcesExpended()
        {
            const int capacity = 4;
            ObjectPool.SetCapacity(capacity);

            for (int index = 0; index < capacity; index++)
            {
                ObjectPool.Acquire();
            }

            try
            {
                ObjectPool.Acquire();
                Assert.Fail("OutOfResourcesException should have been thrown.");
            }
            catch (OutOfResourcesException)
            {
            }
        }

        [TestMethod]
        public void ReleaseBackIntoPool()
        {
            const int capacity = 1;
            ObjectPool.SetCapacity(capacity);
            
            var instance = ObjectPool.Acquire();
            Assert.AreEqual(0, ObjectPool.AvailableCount);

            ObjectPool.Release(instance);
            Assert.AreEqual(capacity, ObjectPool.AvailableCount);
        }

        [TestMethod]
        public void AllowAutoExpandOfPool()
        {
            const int capacity = 1;
            ObjectPool.SetCapacity(capacity);
            ObjectPool.AutoExpand = true;

            ObjectPool.Acquire();

            Assert.IsTrue(ObjectPool.AvailableCount > 0);
        }

        [TestMethod]
        public void ReleaseAfterAutoExpandRetainsExpandedPool()
        {
            const int capacity = 1;
            ObjectPool.SetCapacity(capacity);
            ObjectPool.AutoExpand = true;

            var instance = ObjectPool.Acquire();

            ObjectPool.Release(instance);

            Assert.IsTrue(ObjectPool.AvailableCount > capacity);
        }

        [TestMethod]
        public void AcquireAndReleaseWithinLambda()
        {
            const int capacity = 2;
            ObjectPool.SetCapacity(capacity);
            ObjectPool.LendObject(o =>
                                      {
                                          Assert.IsNotNull(o);
                                          Assert.IsInstanceOfType(o, typeof(PooledObject));
                                          Assert.AreEqual(capacity - 1, ObjectPool.AvailableCount);
                                      });
        }
    }
}
